import type { LayerType, IValues, QueryParams, UrlStr, IdType } from 'aoe';
import Qs from 'qs';
import { layer } from '@layui/layer-vue';

export const GET = 'GET';
export const POST = 'POST';

/**
 * ## 请求类型
 */
export type RequestType = 'GET' | 'POST';

/**
 * ## 负载 "key1-index1, key2"
 */
export type PayloadType = 'id' | string | '*' | false;

/**
 * # Command 命令
 */
export interface ICommand {
  /**
   * 请求路径
   */
  url?: UrlStr;
  /**
   * 请求方式 post/get
   */
  type?: RequestType;
  /**
   * 负载
   */
  payload?: PayloadType;

  /**
   * 指令，视图自己处理
   */
  directive?: 'redirect' | string;
  /**
   * 图层
   */
  layer?: LayerType;
}

/**
 * # 响应结果格式
 */
export interface IResponse<T = unknown> {
  redirect?: UrlStr;
  /**
   * 返回值
   */
  data?: T;
  /**
   * 错误指示
   */
  error?: boolean;
  /**
   * 提示信息
   */
  message?: string;
}

async function _web_get<T =unknown>(
  url?: string,
  query?: QueryParams,
  abort?: AbortController,
) {
  const init = {
    method: 'GET',
  } as RequestInit;

  return await _exec_fetch<T>(_append_url(url, query), init, abort);
}

async function _web_post<T =unknown>(
  url?: string,
  value?: IValues,
  abort?: AbortController,
) {
  const init = {
    headers: {
      'Content-Type': 'application/json;charset=utf-8',
    },
    method: 'POST',
    body: JSON.stringify(value),
  } as RequestInit;

  return await _exec_fetch<T>(url, init, abort);
}


// noinspection JSUnusedGlobalSymbols
/**
 * ## 执行命令
 */
export const web_connector = {
  get: _web_get,

  post: _web_post,

  /**
   *
   */
  invoke: async <T = unknown>(
    command: ICommand,
    value?: IValues,
    abort?: AbortController,
  ) => {
    return command.type === POST
      ? _web_post<T>(command.url, value, abort)
      : _web_get<T>(command.url, _payload2query(command, value), abort);
  },
};

/**
 * 设置请求参数
 */
function _payload2query(
  command: ICommand,
  row?: IValues,
): undefined | QueryParams {
  const payload = command.payload;

  if (!payload || payload === '!') return undefined;

  if (payload === '*') return row as QueryParams;

  if (payload === 'id') return { id: row?.id as IdType };

  if (payload === 'ids') return { ids: row?.ids as IdType[] };

  const r: QueryParams = {};
  payload.split(',').forEach((key) => {
    const [n, v = key] = key.split('-');
    if (row?.[v.trim()] !== undefined) r[n.trim()] = row?.[v.trim()] as string;
  });
  return r;
}

function _append_url(url?: string, query?: QueryParams) {
  if (!query) return url;

  return `${url}?${Qs.stringify(query)}`;
}

function _on_err(message: string) {
  try {
   layer.msg(message,  { icon : 2, time: 1000});
  } catch {
    console.log(message);
  }
}

async function _exec_fetch<T = unknown>(
  url?: UrlStr,
  init?: RequestInit,
  abort?: AbortController,
) {
  if (!url) {
    layer.msg('找不到的URL',  { icon : 2, time: 1000});
    return;
  }

  if (!init) init = {} as RequestInit;

  // 终止信号
  if (abort) init.signal = abort.signal;
  // 跨域cookie
  init.credentials = 'include';
  // 跨域
  init.mode = 'cors';

  try {
    const response = await fetch(url, init);

    // 服务器返回错误状态码
    if (!response.ok) {
      _on_err('服务器内部错误');
      return;
    }

    const data = await response.json() as IResponse;
    if (!data) return;

    if (data.message) {
      layer.msg(data.message,  { icon : data.error ? 2 : 1, time: 1000});
    }

    return data.data as T;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
  } catch (e: any) {
    _on_err(e.message);
  }
}
